package cn.nfwx.tv.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.audiofx.Visualizer;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import java.util.Random;

import cn.nfwx.tv.util.LogUtil;

/**
 * 广播动态图
 * Created by zhouzechao on 2018/1/6.
 */

public class AudioVisualView extends View implements Visualizer.OnDataCaptureListener, Handler.Callback {

    private static final int DN_W = 470;//view宽度与单个音频块占比 - 正常480 需微调
    private static final int DN_H = 360;//view高度与单个音频块占比
    private static final int DN_SL = 1;//单个音频块宽度
    private static final int DN_SW = 3;//单个音频块高度

    private int hgap = 0;
    private int vgap = 0;
    private int levelStep = 0;
    private float strokeWidth = 0;
    private float strokeLength = 0;

    protected final static int MAX_LEVEL = 60;//音量柱·音频块 - 最大个数

    protected final static int CYLINDER_NUM = 20;//音量柱 - 最大个数

    protected Visualizer mVisualizer = null;//频谱器

    protected Paint mPaint = null;//画笔

    protected byte[] mData = new byte[CYLINDER_NUM];//音量柱 数组
    protected int[] mMaxs = new int[CYLINDER_NUM];// 音量柱 最大数
    protected int[] distance = new int[CYLINDER_NUM]; // 方向

    private int UP = 0;
    private int DOWN = 1;

    boolean mDataEn = true;

    Handler _Handler = new Handler(this);

    //构造函数初始化画笔
    public AudioVisualView(Context context) {
        this(context, null);
    }

    public AudioVisualView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AudioVisualView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mPaint = new Paint();//初始化画笔工具
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setColor(Color.WHITE);//画笔颜色

        mPaint.setStrokeJoin(Paint.Join.ROUND); //频块圆角
        mPaint.setStrokeCap(Paint.Cap.ROUND); //频块圆角
    }


    //执行 Layout 操作
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        float w, h, xr, yr;

        w = right - left;
        h = bottom - top;
        xr = w / (float) DN_W;
        yr = h / (float) DN_H;

        strokeWidth = DN_SW * yr;
        strokeLength = DN_SL * xr;
        hgap = (int) ((w - strokeLength * CYLINDER_NUM) / (CYLINDER_NUM + 1));
        vgap = (int) (h / (MAX_LEVEL + 2));//频谱块高度

        mPaint.setStrokeWidth(strokeWidth); //设置频谱块宽度
    }

    //绘制频谱块和倒影
    protected void drawCylinder(Canvas canvas, float x, byte value) {
        if (value == 0) {
            return;
        }//最少有一个频谱块
//        for (int i = 0; i < value; i++) { //每个能量柱绘制value个能量块
//            float y = (getHeight() / 2 - i * vgap);//计算y轴坐标
//            float y1 = (getHeight() / 2 + i * vgap);
//            //绘制频谱块
//            mPaint.setColor(Color.WHITE);//画笔颜色
//            canvas.drawLine(x, y, (x + strokeLength), y, mPaint);//绘制频谱块
//
//            //绘制音量柱倒影
//            if (i <= 8 && value > 0) {
//                mPaint.setColor(Color.WHITE);//画笔颜色
//                mPaint.setAlpha(100 - (100 / 8 * i));//倒影颜色
//                canvas.drawLine(x, y1, (x + strokeLength), y1, mPaint);//绘制频谱块
//            }
//        }
        float y = (getHeight() / 2 - vgap);//计算y轴坐标
        float y1 = (getHeight() / 2);
        //绘制频谱块
        mPaint.setColor(Color.WHITE);//画笔颜色
        mPaint.setAlpha(153);
        canvas.drawLine(x, y - value * vgap, x, y, mPaint);//绘制频谱块
        mPaint.setColor(Color.WHITE);
        mPaint.setAlpha(41);
        canvas.drawLine(x, y1, x, y1 + value * vgap, mPaint);
    }

    @Override
    public void onDraw(Canvas canvas) {
        int j = -4;
        for (int i = 0; i < CYLINDER_NUM / 2 - 4; i++) { //绘制25个能量柱

            drawCylinder(canvas, strokeWidth / 2 + hgap + i * (hgap + strokeLength), mData[i]);
        }
        for (int i = CYLINDER_NUM; i >= CYLINDER_NUM / 2 - 4; i--) {
            j++;
            drawCylinder(canvas, strokeWidth / 2 + hgap + (CYLINDER_NUM / 2 + j - 1) * (hgap + strokeLength), mData[i - 1]);
        }
    }

    Random random = new Random();

    public void autoData() {
        _Handler.removeMessages(2);
        _Handler.removeMessages(1);
        _Handler.sendEmptyMessageDelayed(1, 80);
    }

    public void cancelAutoData() {
        _Handler.removeMessages(1);
        _Handler.removeMessages(2);
        _Handler.sendEmptyMessageDelayed(2, 80);
    }

    public void setVisualizer(Visualizer visualizer) {
        if (visualizer != null) {
            if (!visualizer.getEnabled()) {
                visualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[0]);
            }
            levelStep = 230 / MAX_LEVEL;
            visualizer.setDataCaptureListener(this, Visualizer.getMaxCaptureRate() / 2, false, true);

        } else {

            if (mVisualizer != null) {
                mVisualizer.setEnabled(false);
                mVisualizer.release();
            }
        }
        mVisualizer = visualizer;
    }

    //这个回调应该采集的是快速傅里叶变换有关的数据
    @Override
    public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
        byte[] model = new byte[fft.length / 2 + 1];
        if (mDataEn) {
            model[0] = (byte) Math.abs(fft[1]);
            int j = 1;
            for (int i = 2; i < fft.length; ) {
                model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);
                i += 2;
                j++;
            }
        } else {
            for (int i = 0; i < CYLINDER_NUM; i++) {
                model[i] = 0;
            }
        }
        for (int i = 0; i < CYLINDER_NUM; i++) {
            final byte a = (byte) (Math.abs(model[CYLINDER_NUM - i]) / levelStep);

            final byte b = mData[i];
            if (a > b) {
                mData[i] = a;
            } else {
                if (b > 0) {
                    mData[i]--;
                }
            }
        }
        postInvalidate();//刷新界面
    }

    //这个回调应该采集的是波形数据
    @Override
    public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
        // Do nothing...
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case 1: // 播放
                for (int i = 0; i < CYLINDER_NUM; i++) { //绘制25个能量柱
                    int d = mData[i];
                    if (d == 0) {
                        mMaxs[i] = (byte) random.nextInt(20);
                        distance[i] = UP;
                        d++;
                        mData[i] = (byte) d;
                    } else {
                        if (distance[i] == UP) {
                            int max = mMaxs[i];
                            if (d < max) {
                                d++;
                                mData[i] = (byte) d;
                            } else {
                                distance[i] = DOWN;
                                d--;
                                mData[i] = (byte) d;
                            }
                        } else if (distance[i] == DOWN) {
                            d--;
                            mData[i] = (byte) d;
                        }
                    }
                }
                postInvalidate();
                _Handler.sendEmptyMessageDelayed(1, 80);
                break;
            case 2: // 暂停
                boolean isNext = false;
                for (int i = 0; i < CYLINDER_NUM; i++) { //绘制25个能量柱
                    int d = mData[i];
                    if (d == 0) {

                    } else {
                        isNext = true;
                        d--;
                        mData[i] = (byte) d;
                    }
                }
                postInvalidate();
                if (isNext) {
                    _Handler.sendEmptyMessageDelayed(2, 80);
                }
                break;
        }
        return false;
    }
}
